/*
 * ChessGame.cpp
 *
 *  Created on: Mar 8, 2011
 *      Author: Michael Ziminsky
 */

#include "ChessGame.h"
#include "model/pieces/King.h"
#include <fstream>
#include "MoveParser.h"

bool ChessGame::addPiece(const model::Location& l, const myTypes::cPiece p)
{
	bool valid = !gameBoard.getPieceAt(l) && validatePiece(p);
	if (valid)
	{
		gameBoard.setPiece(l, p);
		//std::cout << *p << l << std::endl;
	}
	return valid;
}

bool ChessGame::validatePiece(const myTypes::cPiece& p)
{
	bool valid;
	if (p->isLight && (valid = lights.size() < ChessGame::MAXPLAYERPIECES))
	{
		if (typeid(*p) == typeid(model::piece::King) && (valid = !lKing)) lKing = p;
		if (valid) lights.insert(lights.end(), p);
	}
	else if ((valid = darks.size() < ChessGame::MAXPLAYERPIECES))
	{
		if (typeid(*p) == typeid(model::piece::King) && (valid = !dKing)) dKing = p;
		if (valid) darks.insert(darks.end(), p);
	}
	return valid;
}

bool ChessGame::attemptMove(const model::Location& from, const model::Location& to)
{
	bool valid = true;
	pieceList& use = gameBoard.isLightTurn() ? darks : lights;
	myTypes::cPiece p = gameBoard.getPieceAt(from);
	myTypes::moveSet m;
	if (!p || (p->isLight == gameBoard.isLightTurn() && (m = getValidMoves(from))->find(to) != m->end()))
	{
		gameBoard.setPiece(to, gameBoard.removePieceAt(from));
		use.remove(p);
		gameBoard.switchTurn();
	}
	else valid = false;
	return valid;
}

void ChessGame::newGame()
{
	gameBoard.reset();
	lKing.reset();
	dKing.reset();
	lights.clear();
	darks.clear();
	std::ifstream file("test.txt");
	MoveParser m(file);
	while (m.good())
		m.getNextMove()->execute(*this);
	file.close();
}

myTypes::moveSet ChessGame::getValidMoves(const model::Location& l)
{
	myTypes::moveSet moves;
	const myTypes::cPiece& p = gameBoard.getPieceAt(l);
	if (p)
	{
		moves = p->getPotentialMoves(gameBoard);
		model::ChessBoard tmp(gameBoard);
		pieceList& use = gameBoard.isLightTurn() ? darks : lights;
		myTypes::moveSet::element_type invalid;
		bool turn = gameBoard.isLightTurn();
		for (myTypes::moveSet::element_type::iterator i = moves->begin(); i != moves->end(); i++)
		{
			myTypes::cPiece removed = tmp.removePieceAt(l);
			use.remove(removed);
			tmp.setPiece(*i, removed);
			if (inCheck(turn, tmp)) invalid.insert(*i);
			if (removed) use.push_back(removed);
			tmp.setPiece(l, tmp.removePieceAt(*i));
		}
		moves->erase(invalid.begin(), invalid.end());
	}
	return moves;
}

bool ChessGame::inCheck(bool light, const model::ChessBoard& b)
{
	if (!lKing || !dKing) throw "Missing a king";
	const model::Location* kl;
	const pieceList* use;
	if (light)
	{
		kl = dKing->getLocation();
		use = &darks;
	}
	else
	{
		kl = lKing->getLocation();
		use = &lights;
	}
	for (pieceList::const_iterator i = use->begin(); i != use->end(); i++)
		if ((*i)->getPotentialMoves(b)->count(*kl) > 0)	return true;
	return false;
}

bool ChessGame::inCheckMate(bool light)
{
	const pieceList& use = light ? lights : darks;
	for (pieceList::const_iterator i = use.begin(); i != use.end(); i++)
		if (getValidMoves(*((*i)->getLocation()))->size() > 0) return false;
	return true;
}

int main()
{
	return 0;
}